package com.molichuxing.framework.filter;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Enumeration;

/**
 * 请求过滤器
 * 跨域请求
 * 非法校验
 * @Description
 * @author 林亿建
 * @date 2017年9月7日
 * @time 下午12:00:52
 * @version 1.0.0
 */
public class AuthorFilter implements Filter{
  //域名配置
  private String[] host = {};

  @Override
  public void init(FilterConfig config) throws ServletException {
    host = config.getInitParameter("host").toUpperCase().split(";");
  }

  @Override
  public void destroy() {
    //Do nothing
  }
  
  @Override
  public void doFilter(ServletRequest req, ServletResponse resp,  FilterChain chain)  throws IOException, ServletException {
    HttpServletResponse response = (HttpServletResponse) resp;
    HttpServletRequest request = (HttpServletRequest) req;
    response.setHeader("cache-control", "no-cache");
    response.setHeader("Access-Control-Allow-Origin","*");
    String url = request.getRequestURI();

    boolean isAttack = false;

    //拦劫非资源文件
    if(!this.matchesValidate(url)){
      //POST防跨站脚本攻击（XSS）
      Enumeration<?> e = request.getParameterNames();
      while (e.hasMoreElements()) {
        String key = e.nextElement().toString();
        String value = request.getParameter(key);
        boolean isInvalidateKey = this.matchesInvalidate(key);
        boolean isInvalidateValue =  this.matchesInvalidate(value);
        boolean isVerified = (null != key && isInvalidateKey) || (null != value && isInvalidateValue);
        if(isVerified){
          isAttack = true ;
          break;
        }
      }

      // GET 防跨站脚本攻击（XSS）
      if(!isAttack){
        String getStr = request.getQueryString();
        if(null != getStr && this.matchesInvalidate(getStr)){
          isAttack = true;
        }
      }

      // 防CSRF攻击
      if(!isAttack){
        String header = request.getHeader("Referer");
        if(null != header && !this.matchesHeader(header)){
          isAttack = true;
        }
      }
    }

    //结束
    if (isAttack) {
      throw new RuntimeException("非法请求");
    }

    chain.doFilter(request, response);
  }
  
  /**
   * 匹配所有不合法字符组合
   * @param value
   * @return
   */
  private boolean matchesInvalidate(String value) {
    value = value.toUpperCase();
    value = value.replaceAll("\n", "");
    return  value.contains("<SCRIPT>")
            ||value.contains("<VBSCRIPT>")
            ||value.contains("<JSCRIPT>")
            ||value.contains("<INPUT")
            ||value.contains("<BUTTON")
            ||(!value.matches("^((?!UPDATE).)*$") && !value.matches("^((?!SET).)*$"))
            ||(!value.matches("^((?!SELECT).)*$") && !value.matches("^((?!FROM).)*$"))
            ||(!value.matches("^((?!DELETE).)*$") && !value.matches("^((?!FROM).)*$"))
            ||(!value.matches("^((?!CREATE).)*$") && !value.matches("^((?!VALUES).)*$"))
            ||(!value.matches("^((?!DROP).)*$") && !value.matches("^((?!TABLE).)*$"));
  }
  
  /**
   * 匹配所有合法字符后缀
   * @param value
   * @return
   */
  private boolean matchesValidate(String value) {
    value = value.toUpperCase();
    return value.lastIndexOf(".JS") != -1 
        &&value.lastIndexOf(".CSS") != -1 
        &&value.lastIndexOf(".PNG") != -1 
        &&value.lastIndexOf(".JPG") != -1
        &&value.lastIndexOf(".JPEG") != -1
        &&value.lastIndexOf(".BMP") != -1
        &&value.lastIndexOf(".ICO") != -1; 
  }
  
  /**
   * 匹配字符串开始
   * @param value
   * @return
   */
  private boolean matchesHeader(String value){
    value = value.toUpperCase();
    boolean b = false;
    if(null != host && host.length != 0){
      for(int i=0;i<host.length;i++){
        if(!value.matches(host[i])){
          b = true ; break;
        }
      }
    }
    return b;
  }

}
